package cn.lili.modules.promotion.serviceimpl;

import cn.hutool.core.collection.CollUtil;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.enums.SceneEnums;
import cn.lili.common.utils.CurrencyUtil;
import cn.lili.common.utils.SnowFlake;
import cn.lili.common.vo.PageVO;
import cn.lili.modules.member.client.UserClient;
import cn.lili.modules.member.entity.dos.User;
import cn.lili.modules.operationcenter.client.OperationCenterClient;
import cn.lili.modules.operationcenter.entity.dos.OperationCenter;
import cn.lili.modules.operationcenter.entity.dos.OperationCenterWithdrawal;
import cn.lili.modules.payment.entity.enums.WithdrawStatusEnum;
import cn.lili.modules.promotion.entity.dos.GreenContributionInfo;
import cn.lili.modules.promotion.entity.dos.GreenCount;
import cn.lili.modules.promotion.entity.dos.GreenPool;
import cn.lili.modules.promotion.entity.dos.GreenUnitPrice;
import cn.lili.modules.promotion.entity.enums.GreenAmountInfoStatusEnum;
import cn.lili.modules.promotion.entity.enums.GreenAmountInfoTypeEnum;
import cn.lili.modules.promotion.entity.vos.GreenContributionInfoVO;
import cn.lili.modules.promotion.entity.vos.GreenCountVO;
import cn.lili.modules.promotion.entity.vos.GreenUnitPriceVO;
import cn.lili.modules.promotion.entity.vos.GreenUserVO;
import cn.lili.modules.promotion.mapper.GreenContributionInfoMapper;
import cn.lili.modules.promotion.mapper.GreenCountMapper;
import cn.lili.modules.promotion.service.GreenConfigService;
import cn.lili.modules.promotion.service.GreenCountService;
import cn.lili.modules.promotion.service.GreenPoolService;
import cn.lili.modules.promotion.service.GreenUnitPriceService;
import cn.lili.mybatis.util.PageUtil;
import com.alibaba.fastjson.JSONObject;
import com.api.PayApi;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pojos.AppBalance;
import com.pojos.GOrder;
import com.pojos.UserRes;
import io.swagger.annotations.ApiModelProperty;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author xiangqian
 * @version 1.0
 * @data 2023/12/18 14:17
 */
@Service
@RequiredArgsConstructor
public class GreenCountServiceImpl extends ServiceImpl<GreenCountMapper, GreenCount> implements GreenCountService {

    private final GreenUnitPriceService greenUnitPriceService;
    private final GreenPoolService greenPoolService;
    private final GreenConfigService greenConfigService;
    private final PayApi payApi;
    private final UserClient userClient;
    @Resource
    private RedissonClient redisson;
    @Resource
    private final GreenContributionInfoMapper greenContributionInfoMapper;

    private final OperationCenterClient operationCenterClient;


    /**
     * 查询绿色积分统计数据
     */
    @Override
    public GreenCountVO getGreenCount() {
        //查询用户绿色积分总数
        BigInteger bigInteger = payApi.getAllGMoney(userClient.getOpenIdByFy());
        BigDecimal userScore = new BigDecimal(bigInteger);
        userScore = userScore.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);

        //查询公益绿色积分总数

        AppBalance appBalance = payApi.getAppBalance("fy_ds7d8s9a1031");
        BigDecimal publicBenefitScore = appBalance.getGmoney().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);

        //查询分红奖金绿色积分总数
        GreenPool greenPool = greenPoolService.getGreenPool();
        BigDecimal dividendScore = greenPool != null ? greenPool.getGreenPool() : new BigDecimal(0);

        //查询分红时间
        String confitTime = greenConfigService.getConfigTime();

        //计算已发放绿色积分总数
        BigDecimal scoreAll = userScore.add(publicBenefitScore).add(dividendScore);

        //构建返回结果
        return GreenCountVO.builder().scoreAll(scoreAll).userScore(userScore).publicBenefitScore(publicBenefitScore).dividendScore(dividendScore).configTime(confitTime).build();
    }

    /**
     * 查询贡献值统计数据
     */
    @Override
    public GreenContributionInfoVO getContributionCount() {
        //查询当前最新单价
        BigDecimal newUnitPrice = greenUnitPriceService.getNewUnitPrice();
        //查询贡献值总量
        BigDecimal contributionAllValue = this.getBaseMapper().getContributionAllValue();
        return GreenContributionInfoVO.builder().newUnitPrice(newUnitPrice).contributionAllValue(contributionAllValue).build();
    }

    /**
     * 分页查询贡献值列表
     *
     * @param greenCount 查询条件{@link GreenCount}
     * @param page       分页条件{@link PageVO}
     * @return 分页返回结果
     */
    @Override
    public Page<GreenCount> contributionPage(GreenCount greenCount, PageVO page) {
        return this.baseMapper.selectPage(PageUtil.initPage(page), greenCount.queryWrapperPage());
    }

    /**
     * H5-绿色积分首页
     *
     * @param openId 用户openId
     * @param userId 用户userID
     * @return 返回结果
     */
    @Override
    public GreenUserVO home(String openId, String userId) {
        //查询分红奖金绿色积分总数
        GreenPool greenPool = greenPoolService.getGreenPool();
        BigDecimal dividendScore = greenPool != null ? greenPool.getGreenPool() : new BigDecimal(0);

        //查询分红时间
        String confitTime = greenConfigService.getConfigTime();

        //查询我的绿色积分
        UserRes userRes = payApi.getUserMoney(openId);
        BigDecimal moneyDecimal = new BigDecimal(userRes.getGmoney());
        moneyDecimal = moneyDecimal.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        String gmoney = moneyDecimal.toString();

        //查询我的绿色贡献值
        BigDecimal userContributionAllValue = this.getBaseMapper().getContributionAllValueByUserId(userId);

        //查询我的待结算绿色积分
        BigDecimal userContributionAllValueStay = greenContributionInfoMapper.getUmber(userId);

        //查询最新单价
        BigDecimal newUnitPrice = greenUnitPriceService.getNewUnitPrice();

        //计算预计可分红绿色积分
        BigDecimal predictPrice = new BigDecimal(0);
        BigDecimal temp1 = userContributionAllValue.multiply(newUnitPrice);//我的绿色贡献值 * 单价
        predictPrice = predictPrice.add(temp1).add(userContributionAllValueStay);

        //查询折线图
        List<GreenUnitPriceVO> greenUnitPriceList = greenUnitPriceService.greenUnitPricePicturePage("0");

        //返回
        return GreenUserVO.builder()
                .dividendScore(dividendScore)
                .confitTime(confitTime)
                .gmoney(gmoney)
                .userContributionAllValue(userContributionAllValue)
                .userContributionAllValueStay(userContributionAllValueStay)
                .predictPrice(predictPrice)
                .newUnitPrice(newUnitPrice)
                .greenUnitPriceList(greenUnitPriceList)
                .build();
    }

    /**
     * 绿色积分明细(绿色积分管理-用户)
     *
     * @param gOrder 查询条件{@link GOrder}
     * @param page   分页条件{@link PageVO}
     * @return 分页返回结果
     */
    @Override
    public Page<GOrder> getGreenInfo(GOrder gOrder, PageVO page) {
        Page<GOrder> resultPage = new Page<>();

        JSONObject jsonObject = payApi.getGOrderList(gOrder.getOpenid(), page.getPageNumber(), page.getPageSize(), gOrder.getPayType());
        if (jsonObject.getInteger("code") == 200) {
            String data = jsonObject.getString("data");
            String count = jsonObject.getString("count");
            List<GOrder> list = gOrder.initGOrder(data);
            resultPage.setTotal(Integer.parseInt(count));
            resultPage.setRecords(list);
        }

        resultPage.setPages(page.getPageNumber());
        resultPage.setSize(page.getPageSize());
        return resultPage;
    }

    /**
     * 冻结/解冻绿色积分(绿色积分管理-用户)
     *
     * @param openId  用户openId
     * @param payType 冻结状态 0 解冻， 1 只允许进不允许出， 2 进出都不允许，直接禁用
     * @return 冻结结果
     */
    @Override
    public JSONObject greenFreeze(String openId, Integer payType) {
        return payApi.freeze(openId, payType);
    }

    @Override
    @ApiModelProperty("领取奖金")
    @Transactional
    @ShardingTransactionType(TransactionType.BASE)
    public Boolean getBonus(BigDecimal contributionAllValue, String openId, String userId) {
        RLock lock = null;

        if (SceneEnums.OPERATION_CENTER.name().equals(Objects.requireNonNull(UserContext.getCurrentUser()).getScene().name())) {
            userId = Objects.requireNonNull(UserContext.getCurrentUser()).getId();
        }

        //查询我的绿色贡献值
        BigDecimal userContributionAllValue = this.getBaseMapper().getContributionAllValueByUserId(userId);
        if (userContributionAllValue == null || userContributionAllValue.compareTo(new BigDecimal(0)) == 0) {
            throw new ServiceException("超过最大领取绿色贡献值");
        }
        Assert.isTrue(contributionAllValue.compareTo(userContributionAllValue) < 0, "超过最大领取绿色贡献值");

        try {
            lock = redisson.getLock("GETBONUS_" + userId);
            lock.lock(100, TimeUnit.SECONDS);

            //查询最新单价
            BigDecimal newUnitPrice = greenUnitPriceService.getNewUnitPrice();

            //打款金额扣除手续费
            BigDecimal exchangevalue = greenConfigService.getExchangevalue();
            exchangevalue = exchangevalue.divide(new BigDecimal(100));

            //领取奖金，打款绿色积分
            String attach = "领取奖金";//备注
            int tradeType = 1;//固定值
            int operationType = 101;//用户自定义

            //绿色积分扣除手续费后打款金额
            BigDecimal tempBig = contributionAllValue.multiply(newUnitPrice);
            tempBig = tempBig.subtract(tempBig.multiply(exchangevalue));
            BigInteger money = tempBig.multiply(new BigDecimal(100)).toBigInteger();

            String result = payApi.paymentV2String(openId, attach, money.intValue(), tradeType, operationType, "GMONEY");
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.getInteger("code") != 200) {
                if (jsonObject.getInteger("code") == 10008){
                    throw new ServiceException(ResultCode.NAME_OUTH,jsonObject.getString("msg"));
                }else{
                    throw new ServiceException(jsonObject.getString("msg"));
                }
            }


            //查询用户信息
            User user = userClient.getById(userId);

            //插入绿色贡献值领取记录
            GreenContributionInfo greenContributionInfo = new GreenContributionInfo();
            greenContributionInfo.initGreenContributionInfo(user);
            greenContributionInfo.setType(GreenAmountInfoTypeEnum.CASHING_PRIZE.name());
            greenContributionInfo.setUmber(contributionAllValue);
            greenContributionInfo.setStatus(GreenAmountInfoStatusEnum.DISBURSE.name());
            greenContributionInfo.setScoreNumber(contributionAllValue.multiply(newUnitPrice));
            greenContributionInfo.setUserType(user.getScene());
            //greenContributionInfoMapper.insert(greenContributionInfo);

            //减少绿色积分池
            greenPoolService.removeGreenPool(contributionAllValue.multiply(newUnitPrice));

            if (SceneEnums.OPERATION_CENTER.name().equals(Objects.requireNonNull(UserContext.getCurrentUser()).getScene().name())) {
                // 记录绿色积分变动记录
                OperationCenterWithdrawal operationCenterWithdrawal = new OperationCenterWithdrawal();
                OperationCenter operationCenter = operationCenterClient.getOperationCenter(userId);
                operationCenterWithdrawal.setOperationId(operationCenter.getId());
                operationCenterWithdrawal.setUserId(operationCenter.getUserId());
                operationCenterWithdrawal.setOperationName(operationCenter.getOperationName());
                operationCenterWithdrawal.setMoney(Double.valueOf(String.valueOf(tempBig)));
                operationCenterWithdrawal.setRemarks(operationCenter.getOperationName() + "-兑换绿色积分");
                operationCenterWithdrawal.setOrderNo(SnowFlake.createStr("DH"));
                operationCenterWithdrawal.setStatus(WithdrawStatusEnum.VIA_AUDITING.name());
                operationCenterWithdrawal.setGreenScoreType(GreenAmountInfoStatusEnum.INCOME.name());
                UserRes userRes = payApi.getUserMoney(Objects.requireNonNull(UserContext.getCurrentUser()).getOpenId());
                Double before = CurrencyUtil.sub(CurrencyUtil.div(Double.parseDouble(userRes.getGmoney()), 100), Double.parseDouble(String.valueOf(greenContributionInfo.getScoreNumber())));
                operationCenterWithdrawal.setBeforeMoney(before);
                operationCenterWithdrawal.setAfterMoney(CurrencyUtil.div(Double.parseDouble(userRes.getGmoney()), 100));
                operationCenterClient.insertWithdrawal(operationCenterWithdrawal);
            }



            //减少我的绿色贡献值
            GreenCount queryGreenCount = new GreenCount();
            queryGreenCount.setUserId(userId);
            GreenCount greenCount = this.getBaseMapper().selectOne(queryGreenCount.queryWrapperPage());
            greenCount.setUmber(greenCount.getUmber().subtract(contributionAllValue));
            //记录兑换绿色积分的贡献值支出记录
            greenContributionInfo.setAfterBalance(greenCount.getUmber());
            greenContributionInfoMapper.insert(greenContributionInfo);

            greenCount.setHasUmber(greenCount.getHasUmber()!=null?greenCount.getHasUmber().add(contributionAllValue):contributionAllValue);
            return this.updateById(greenCount);
        }finally {
            if (lock != null) {
                lock.unlock();
            }
        }
    }

    /**
     * 计算可得绿色积分
     *
     * @param contributionAllValue 要领取的贡献值
     */
    @Override
    public BigDecimal computeBonus(BigDecimal contributionAllValue) {
        if (contributionAllValue == null) {
            throw new ServiceException("我的绿色贡献值为空");
        }
        //查询手续费
        BigDecimal exchangevalue = greenConfigService.getExchangevalue();
        exchangevalue = exchangevalue.divide(new BigDecimal(100));

        //查询最新单价
        BigDecimal newUnitPrice = greenUnitPriceService.getNewUnitPrice();

        //计算预计可分红绿色积分
        BigDecimal temp = contributionAllValue.multiply(newUnitPrice);//我的绿色贡献值 * 单价
        temp = temp.subtract(temp.multiply(exchangevalue));
        return temp;
    }

    /**
     * 自动分红
     *
     * @return 返回结果
     */
    @Override
    @Transactional
    @ShardingTransactionType(TransactionType.BASE)
    public Boolean autoDividend() {
        //查询最新单价
        BigDecimal newUnitPrice = greenUnitPriceService.getNewUnitPrice();

        //打款金额扣除手续费
        BigDecimal dividendvalue = greenConfigService.getDividendvalue();
        dividendvalue = dividendvalue.divide(new BigDecimal(100));

        //查询所有用户贡献值
        List<GreenCount> greenCountList = this.getBaseMapper().getContributionAllValueAll();
        for (GreenCount greenCount:greenCountList) {
            //查询用户
            User user = userClient.getById(greenCount.getUserId());

            //领取奖金，打款绿色积分
            String attach = "自动分红";//备注
            int tradeType = 1;//固定值
            int operationType = 102;//用户自定义

            //绿色积分扣除手续费后打款金额
            BigDecimal tempBig = greenCount.getUmber().multiply(newUnitPrice);
            tempBig = tempBig.subtract(tempBig.multiply(dividendvalue));
            BigInteger money = tempBig.multiply(new BigDecimal(100)).toBigInteger();

            //插入绿色贡献值领取记录
            GreenContributionInfo greenContributionInfo = new GreenContributionInfo();
            greenContributionInfo.initGreenContributionInfo(user);
            greenContributionInfo.setType(GreenAmountInfoTypeEnum.AUTO_DIVIDEND.name());
            greenContributionInfo.setUmber(greenCount.getUmber());
            greenContributionInfo.setStatus(GreenAmountInfoStatusEnum.DISBURSE.name());
            greenContributionInfo.setScoreNumber(greenCount.getUmber().multiply(newUnitPrice));
            greenContributionInfoMapper.insert(greenContributionInfo);

            //减少绿色积分池
            greenPoolService.removeGreenPool(greenCount.getUmber().multiply(newUnitPrice));

            //清空我的绿色贡献值
            greenCount.setHasUmber(greenCount.getHasUmber()!=null?greenCount.getHasUmber().add(greenCount.getUmber()):greenCount.getUmber());
            greenCount.setUmber(new BigDecimal(0));
            this.updateById(greenCount);

            //最后再打款
            boolean isok = payApi.paymentV2(user.getOpenId(), attach, money.intValue(), tradeType, operationType, "GMONEY");
            Assert.isTrue(isok, "调用飞语SDK打款失败");
        }

        //清空绿色积分池
        GreenPool greenPool = greenPoolService.getGreenPool();
        GreenContributionInfo greenContributionInfo = new GreenContributionInfo();
        greenContributionInfo.setType(GreenAmountInfoTypeEnum.MANAGE_HANDLE.name());
        greenContributionInfo.setStatus(GreenAmountInfoStatusEnum.DISBURSE.name());
        greenContributionInfo.setScoreNumber(greenPool.getGreenPool());
        greenContributionInfoMapper.insert(greenContributionInfo);

        greenPool.setGreenPool(new BigDecimal(0));
        greenPoolService.updateById(greenPool);

        //清空单价
        GreenUnitPrice greenUnitPrice = new GreenUnitPrice();
        greenUnitPrice.setUnitPrice(new BigDecimal(1));
        greenUnitPrice.setUnitTime(new Date());
        return greenUnitPriceService.save(greenUnitPrice);
    }

    /**
     * 查询我的绿色贡献值
     */
    @Override
    public Double getContributionAllValueByUserId(String userId) {
        //查询我的绿色贡献值
        BigDecimal userContributionAllValue = this.getBaseMapper().getContributionAllValueByUserId(userId);
        if (userContributionAllValue != null) {
            return userContributionAllValue.doubleValue();
        }
        return 0.0;
    }


    //查询我的待结算绿色积分
    @Override
    public Double getSettleUmberByUserId(String userId) {
        BigDecimal userContributionAllValueStay = greenContributionInfoMapper.getUmber(userId);
        if (userContributionAllValueStay != null) {
            return userContributionAllValueStay.doubleValue();
        }
        return 0.0;
    }

    /**
     * 运营中心-绿色积分明细
     * @param page
     * @return
     */
    @Override
    public Page<GOrder> getGreenDetailPage(PageVO page) {
        GOrder gOrder = new GOrder();
        Page<GOrder> resultPage = new Page<>();
        AuthUser authUser = UserContext.getCurrentUser();
        //101 为兑换绿色积分
        JSONObject jsonObject = payApi.getGOrderListByOperationType(authUser.getOpenId(), page.getPageNumber(), page.getPageSize(), 101);
        if (jsonObject.getInteger("code") == 200) {
            String data = jsonObject.getString("data");
            String count = jsonObject.getString("count");
            List<GOrder> list = gOrder.initGOrder(data);
            resultPage.setTotal(Integer.parseInt(count));
            if (CollUtil.isNotEmpty(list)) {
                String remark = "运营中心账号兑换绿色积分";
                list.stream().forEach(e -> {
                    e.setRemarks(remark);
                });
                resultPage.setRecords(list);
                resultPage.setSize(list.size());
            }
        }
        resultPage.setPages(page.getPageNumber());
        return resultPage;
    }
}
